
#include "UpdaterThread.h"
#include "Timer.h"

using namespace std;
using namespace ttg_internal::services;

//---------------------
//--- UpdaterThread ---
//---------------------

template <class Iter>
void getNextEvent(Iter begin, Iter end, double cur_time, TimeEvent *&next_ev)
{
	//Is any event available?
	if (begin == end)
		return;
	//Searching for the first enabled event.
	if (next_ev == NULL)
	{
		while (begin != end &&
			   !(*begin)->isEnabled())
			begin++;
		if (begin == end)
			return;
		next_ev = *begin++;
	}
	//Searching for next event.
	while (begin != end)
	{
		if ((*begin)->isEnabled() &&
			(*begin)->getLeftTime(cur_time) < next_ev->getLeftTime(cur_time))
			next_ev = *begin;
		begin++;
	}
}

double UpdaterThread::determineCurrent()
{
	current = NULL;
	double cur_time = ttg::services::Timer::getRef()->getSeconds();
	getNextEvent(continuous_events.begin(), continuous_events.end(), cur_time, current);
	getNextEvent(noncontinuous_events.begin(), noncontinuous_events.end(), cur_time, current);
	return current != NULL ? current->getLeftTime(cur_time) : -1.0;
}

void UpdaterThread::work()
{
	sleepDeep();
	while (true)
	{
		//Getting current event.
		locker.enter();
		double sleep_time = determineCurrent();
		locker.leave();
		//Waiting for event.
		if (current == NULL)
			sleepDeep(); else
		if (sleep_time > 0.0)
			sleepDeep(sleep_time);
		//Checking modifications.
		if (was_modified)
		{
			was_modified = false;
			continue;
		}
		//Notifying.
		if (current != NULL)
		{
			current->notify(ttg::services::Timer::getRef()->getSeconds());
			if (!current->isContinual())
			{
				locker.enter();
				noncontinuous_events.remove(current);
				locker.leave();
				SAFE_DELETE(current);
			}
			current = NULL;
		}
	}
}

template <class Iter>
TimeEvent *findEvent(Iter begin, Iter end, TimeEvent *ev)
{
	while (begin != end)
	{
		if (*begin == ev)
			return ev;
		begin++;
	}
	return NULL;
}

TimeEvent *UpdaterThread::find(ttg::math::uint64 ID)
{
	if (findEvent(continuous_events.begin(), continuous_events.end(), (TimeEvent *)ID))
		return (TimeEvent *)ID; else
	if (findEvent(noncontinuous_events.begin(), noncontinuous_events.end(), (TimeEvent *)ID))
		return (TimeEvent *)ID;
	else
		return NULL;
}

ttg::math::uint64 UpdaterThread::addEvent(TimeEvent *ev)
{
	locker.enter();
	if (ev->isContinual())
		continuous_events.push_back(ev);
	else
		noncontinuous_events.push_back(ev);
	if (ev->isEnabled())
	{
		was_modified = true;
		wake();
	}
	locker.leave();
	return (ttg::math::uint64)ev;
}

void UpdaterThread::enableEvent(ttg::math::uint64 ID)
{
	TimeEvent *ev;
	locker.enter();
	if ((ev = find(ID)) != NULL &&
		!ev->isEnabled())
	{
		ev->setEnabled(true);
		was_modified = true;
		wake();
	}
	locker.leave();
}

void UpdaterThread::disableEvent(ttg::math::uint64 ID)
{
	TimeEvent *ev;
	locker.enter();
	if ((ev = find(ID)) != NULL &&
		ev->isEnabled())
	{
		ev->setEnabled(false);
		was_modified = true;
		wake();
	}
	locker.leave();
}

UpdaterThread::~UpdaterThread()
{
	locker.enter();
	//Deleting continuous events.
	for (size_t i = 0; i < continuous_events.size(); i++)
		SAFE_DELETE(continuous_events[i]);
	continuous_events.clear();
	//Deleting non-continuous events.
	list<TimeEvent *>::iterator it = noncontinuous_events.begin();
	while (it != noncontinuous_events.end())
	{
		SAFE_DELETE(*it);
		it++;
	}
	noncontinuous_events.clear();
	locker.leave();
}
